package controllers

/**
 * Created by yz on 2017/5/31.
 */

import command.CommandExec
import dao._
import implicits.Implicits._
import play.api.mvc._
import tool.Pojo.CommandData
import tool.{FormTool, Tool}
import utils.Utils

import java.io.File
import javax.inject.Inject
import scala.collection.immutable.SeqMap
import scala.concurrent.ExecutionContext.Implicits.global
import implicits.Implicits._
import shared.Pojo._
import shared.tsPojo.TsPojo
import ujson.play.PlayJson
import upickle.default._

class AnalysisController @Inject()(cc: ControllerComponents)(
  implicit val geneExpDao: GeneExpDao,
  implicit val genesDao: GenesDao,
  implicit val browseGeneDao: BrowseGeneDao,
  implicit val mTissueDataDao: MTissueDataDao,
  implicit val hTissueDataDao: HTissueDataDao,
  implicit val cellLineExprDao: CellLineExprDao,
  implicit val survExprDao: SurvExprDao,
  implicit val iccSurvExprDao: IccSurvExprDao,
  implicit val modeDao: ModeDao,

) extends AbstractController(cc) {

  import TsPojo.analysis._

  def getAllGene = Action.async { implicit request =>
    val data = FormTool.qForm.bindFromRequest().get
    val pageSize = data.pageSize
    cellLineExprDao.selectAllGene(data).map { x =>
      val trueX = x.sorted.sortWith((t, z) => {
        (data.q.size.toDouble / t.size) > (data.q.size.toDouble / z.size)
      }).drop((data.page - 1) * pageSize).take(pageSize)
      val results = trueX.map { y =>
        ujson.Obj("id" -> y, "text" -> y)
      }
      val more = pageSize * data.page < x.size
      Ok(ujson.Obj("results" -> results, "pagination" -> ujson.Obj("more" -> more)))
    }

  }

  def allGene = Action.async { implicit request =>
    val queryMap = request.queryString.map { case (k, v) =>
      (k, v.head)
    }
    val data = writeJs(queryMap).transform(reader[AllGene.Request])
    val pageSize = data.pageSize
    val f = data.species match {
      case "Hsa" => hTissueDataDao.selectAllGene(data)
      case "Mmu" => mTissueDataDao.selectAllGene(data)
    }
    f.map { x =>
      val trueX = x.sorted.sortWith((t, z) => {
        (data.q.size.toDouble / t.size) > (data.q.size.toDouble / z.size)
      }).drop((data.page - 1) * pageSize).take(pageSize)
      val results = trueX.map { y =>
        ujson.Obj("id" -> y, "text" -> y)
      }
      val more = pageSize * data.page < x.size
      Ok(ujson.Obj("results" -> results, "pagination" -> ujson.Obj("more" -> more)))
    }

  }

  def cellLineDepImage = Action { implicit request =>
    val startTime = System.currentTimeMillis()
    val data = PlayJson.transform(request.body.asJson.get, reader[CellLineDepImage.Request])
    val tmpDir = Tool.createTempDirectory("tmpDir")
    val pngFile = new File(tmpDir, "out.png")
    val colorFile = new File(Tool.cellLineDepDir, "pal1.txt")
    val inputFile = new File(Tool.cellLineDepDir, "CCLE_liver_dependency.txt")
    val command =
      s"""
         |${"Rscript".condaPath()} ${Tool.rPath.unixPath}/cell_line_dep.R --i ${inputFile.unixPath} --c ${colorFile.unixPath} --order ${data.order} --g ${data.geneName}  --o ${pngFile.unixPath}
         |""".stripMargin
    val commandExec = CommandExec().exec { b =>
      CommandData(tmpDir, command)
    }
    val response = if (commandExec.isSuccess) {
      println("exec complete:", Utils.getTime(startTime))
      val base64 = pngFile.base64
      val geneData = new File(tmpDir, "gene.csv").str
      CellLineDepImage.Response(valid = true, base64 = base64, geneData = geneData)
    } else {
      CellLineDepImage.Response(valid = false, message = commandExec.errorInfo)
    }
    Tool.deleteDirectory(tmpDir)
    Ok(writeJs(response))

  }

  def cellLineScatterImage = Action { implicit request =>
    val startTime = System.currentTimeMillis()
    val data = PlayJson.transform(request.body.asJson.get, reader[CellLineScatterImage.Request])
    val tmpDir = Tool.createTempDirectory("tmpDir")
    val pngFile = new File(tmpDir, "out.png")
    val depFile = new File(Tool.cellLineDepDir, "CCLE_liver_dependency.txt")
    val exprFile = new File(Tool.cellLineDepDir, "Cellline_dep_overlap_expr.txt")
    val command =
      s"""
         |${"Rscript".condaPath()} ${Tool.rPath.unixPath}/cell_line_scatter.R --d ${depFile.unixPath} --e ${exprFile.unixPath} --g ${data.geneName} --x "${data.xAxis}" --y "${data.yAxis}" --l ${data.linear} --o ${pngFile.unixPath}
         |""".stripMargin
    val commandExec = CommandExec().exec { b =>
      CommandData(tmpDir, command)
    }
    val response = if (commandExec.isSuccess) {
      println("exec complete:", Utils.getTime(startTime))
      val base64 = pngFile.base64
      val geneData = new File(tmpDir, "gene.csv").str
      CellLineScatterImage.Response(valid = true, base64 = base64, geneData = geneData)
    } else {
      CellLineScatterImage.Response(valid = false, message = commandExec.errorInfo)
    }
    Tool.deleteDirectory(tmpDir)
    Ok(writeJs(response))
  }

  def survivalImage = Action.async { implicit request =>
    val startTime = System.currentTimeMillis()
    val data = PlayJson.transform(request.body.asJson.get, reader[SurvivalImage.Request])
    survExprDao.selectAll(data.geneName).zip(iccSurvExprDao.selectAll(data.geneName)).map { case (rows, iccRows) =>
      val tmpDir = Tool.createTempDirectory("tmpDir")
      val pngFile = new File(tmpDir, "out.png")
      val ieFile = new File(tmpDir, "icc_expr.txt")
      val exprFile = new File(tmpDir, "expr.txt")
      val survFile = new File(Tool.dataDir, "Gepliver_surv_all.txt")
      val maps = rows.map { row =>
        SeqMap("gene" -> row.gene) ++ Tool.json2SeqMap(row.value)
      }.toList
      maps.csvLines.toTxtFile(exprFile)
      iccRows.map { row =>
        SeqMap("gene" -> row.gene) ++ Tool.json2SeqMap(row.value)
      }.toList.csvLines.toTxtFile(ieFile)
      val command =
        s"""
           |${"Rscript".condaPath("gep_liver")} ${Tool.rPath.unixPath}/survival.R --ie ${ieFile.unixPath} --e ${exprFile.unixPath} --surv ${survFile.unixPath} --g ${data.geneName} --t ${data.tumorType} --d "${data.dataset}" --s ${data.survivalData} --u "${data.upperCutoff}" --l "${data.lowerCutoff}" --o ${pngFile.unixPath}
           |""".stripMargin
      val commandExec = CommandExec().exec { b =>
        CommandData(tmpDir, command)
      }
      val response = if (commandExec.isSuccess) {
        println("exec complete:", Utils.getTime(startTime))
        val base64 = pngFile.base64
        val geneData = new File(tmpDir, "gene.csv").str
        SurvivalImage.Response(valid = true, base64 = base64, geneData = geneData)
      } else {
        SurvivalImage.Response(valid = false, message = commandExec.errorInfo)
      }
      Tool.deleteDirectory(tmpDir)
      Ok(writeJs(response))
    }
  }

  def comparisonImage = Action.async { implicit request =>
    val startTime = System.currentTimeMillis()
    val data = PlayJson.transform(request.body.asJson.get, reader[ComparisonImage.Request])
    hTissueDataDao.selectAll(data.geneName).zip(mTissueDataDao.selectAll(data.geneName)).map { case (rows, mRows) =>
      val tmpDir = Tool.createTempDirectory("tmpDir")
      val pngFile = new File(tmpDir, "out.png")
      val mFile = new File(tmpDir, "m_expr.txt")
      val hBulkExprFile = new File(tmpDir, "h_expr.txt")
      val hmFile = new File(Tool.dataDir, "hbulk_meta.txt")
      val mmFile = new File(Tool.dataDir, "mbulk_meta.txt")
      rows.map { row =>
        SeqMap("gene" -> data.geneName) ++ Tool.json2SeqMap(row.value)
      }.toList.csvLines.toTxtFile(hBulkExprFile)
      mRows.map { row =>
        SeqMap("gene" -> data.geneName) ++ Tool.json2SeqMap(row.value)
      }.toList.csvLines.toTxtFile(mFile)
      val command =
        s"""
           |${"Rscript".condaPath()} ${Tool.rPath.unixPath}/comparison.R --h ${hBulkExprFile.unixPath} --m ${mFile.unixPath} --hm ${hmFile.unixPath} --mm ${mmFile.unixPath} --g ${data.geneName} --s ${data.species} --hap "${data.haps.mkString(";")}" --hbp "${data.hbps.mkString(";")}" --had "${data.hads.mkString(";")}" --hbd "${data.hbds.mkString(";")}" --t ${data.testMethod} --l ${data.log} --map "${data.maps.mkString(";")}" --mbp "${data.mbps.mkString(";")}" --mad "${data.mads.mkString(";")}" --mbd "${data.mbds.mkString(";")}" --mam "${data.mams.mkString(",")}" --mbm "${data.mbms.mkString(",")}" --o ${pngFile.unixPath}
           |""".stripMargin
      val commandExec = CommandExec().exec { b =>
        CommandData(tmpDir, command)
      }

      val response = if (commandExec.isSuccess) {
        println("exec complete:", Utils.getTime(startTime))
        val base64 = pngFile.base64
        val geneData = new File(tmpDir, "gene.csv").str
        ComparisonImage.Response(valid = true, base64 = base64, geneData = geneData)
      } else {
        ComparisonImage.Response(valid = false, message = commandExec.errorInfo)
      }
      Tool.deleteDirectory(tmpDir)
      Ok(writeJs(response))
    }
  }

}
